package selector

import (
	"context"
	"errors"
	"sync"
	"sync/atomic"
)

// 轮询
type RoundRobin struct {
	nodeCount int // 节点数量
	nextIndex int // 下一个节点的索引
	mux       sync.Mutex
	nodes     atomic.Value
}

type RoundRobinBuilder struct {
	rr *RoundRobin
}

func NewRoundRobinBuilder() Builder {
	return &RoundRobinBuilder{}
}

func (rr *RoundRobinBuilder) Build() Selector {
	return NewRoundRobin()
}

func NewRoundRobin() Selector {
	return &RoundRobin{
		nodeCount: 0,
		nextIndex: 0,
	}
}

func (rr *RoundRobin) Add(nodes ...Node) error {
	if len(nodes) == 0 {
		return errors.New("params len 1 at least")
	}
	rr.mux.Lock()
	defer rr.mux.Unlock()
	//可以在赋值之前加一个输入参数正确性判断
	rr.nodes.Store(nodes)
	n := rr.nodes
	if n.Load() == nil {
		return errors.New("NODE_NOT_FOUND")
	}
	ns := n.Load().([]Node)
	if len(ns) == 0 {
		return errors.New("node len 0")
	}
	rr.nodeCount = len(ns)
	rr.nextIndex = 0
	return nil
}

func (rr *RoundRobin) Next(ctx context.Context) (selected Node, err error) {
	rr.mux.Lock()
	defer rr.mux.Unlock()
	n := rr.nodes
	if n.Load() == nil {
		return nil, errors.New("NODE_NOT_FOUND")
	}
	nodes := n.Load().([]Node)
	if len(nodes) == 0 {
		return nil, errors.New("node len 0")
	}
	node := nodes[rr.nextIndex]
	rr.nextIndex = (rr.nextIndex + 1) % rr.nodeCount
	peer, ok := FromPeerContext(ctx)
	if ok {
		peer.Node = node
	}
	return node, nil
}
